/* vim: set expandtab shiftwidth=4: -*- mode: c++; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: nil -*-
qRPG
An RPG written to test Qt's Graphics View framework
Copyright (C) 2006 Wesley Crossman
Email: wesley@crossmans.net

You can redistribute and/or modify this software under the terms of the GNU
General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this
program; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
Suite 330, Boston, MA 02111-1307 USA */

#include "itemeffects.h"
#include "GameBoardScene.h"
#include "BoardEntry.h"
#include "BoardCharacter.h"
#include "qmath.h"
#include <QGraphicsItem>
#include <QtCore>
class ItemMover;

QMap < GameBoardScene *, ItemMover * > ItemMover::instances;

ItemMover *ItemMover::instance(GameBoardScene *scene) {
    ItemMover *instance = instances.value(scene);
    if (!instance) {
        instance = new ItemMover(scene);
        instances[scene] = instance;
    }
    return instance;
}

void ItemMover::deleteInstances() {
    foreach (ItemMover *mover, instances) {delete mover;}
    instances.clear();
}

ItemMover::ItemMover(GameBoardScene *scene) {
    this->scene = scene;
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), SLOT(step()));
}

void ItemMover::move(GameItem *item, QPoint from, QPoint to, int steps) {
    entries[item] = new MoveEntry(item, from, to, steps);
}

void ItemMover::step() {
    QList < MoveEntry * > values = entries.values();
    foreach (MoveEntry *entry, values) {
        ++entry->index;
        QPointF physFrom = scene->toPhysical(entry->from);
        QPointF physTo = scene->toPhysical(entry->to);
        if (entry->index == entry->steps) {
            entry->item->item->setPos(physTo);
            GameItem *key = entry->item;
            delete entry;
            entries.remove(key);
        } else {
            QPointF step = (physTo - physFrom) / entry->steps;
            entry->item->item->setPos(physFrom + step * entry->index);
        }
    }
}

Effect::Effect(QGraphicsItem *parent, GameBoardScene *scene) {
    phase = 0;
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), SLOT(timerFired()));
}

Star::Star(qreal x, qreal y, QGraphicsItem *parent, GameBoardScene *scene)
            : Effect(parent, scene) {
    timer->start(50);

    QVector < QPointF > points;
    points.append(QPointF(4.2931481,7.5399723));
    points.append(QPointF(0.96509887,5.7227111));
    points.append(QPointF(-2.4186397,7.434045));
    points.append(QPointF(-1.7187453,3.7073174));
    points.append(QPointF(-4.3919533,1.0180221));
    points.append(QPointF(-0.63134552,0.53203907));
    points.append(QPointF(1.1002596,-2.8413708));
    points.append(QPointF(2.7245487,0.58500275));
    points.append(QPointF(6.4679475,1.1894161));
    points.append(QPointF(3.7112056,3.7930145));
    points.append(QPointF(4.2931481,7.5399723));
    QPolygonF polygon(points);
    polygon.translate(-1, -3);
    /*QGraphicsRectItem *rect = new QGraphicsRectItem(-1, -1, 2, 2, NULL, scene);
    rect->setPos(x, y);
    rect->setPen(QPen(Qt::black));
    rect->setZValue(scene->getLayerIndex("walls")*10+3);*/
    star = new QGraphicsPolygonItem(polygon, parent, scene);
    star->setPos(x, y);
    QPen pen(Qt::black);
    pen.setWidth(4);
    star->setPen(QPen(Qt::black));
    star->setBrush(QBrush(QColor(255, 127, 0)));
    star->scale(5.0, 5.0);
    star->setZValue(scene->getLayerIndex("walls")*10+3);
    advance(0);
}

Star::~Star() {
    delete star;
}

void Star::timerFired() {
    phase += 1;
    advance(phase);
}

void Star::advance(int phase) {
    const int max = 15;
    QMatrix matrix;
    matrix.rotate(qreal(phase-1) * (270/max));
    qreal percent = qreal(max-phase)/max;
    matrix.scale(percent * 4.0, percent * 4.0);
    star->setMatrix(matrix);
    
    QColor fill = star->brush().color();
    fill.setAlpha(percent * 255);
    star->setBrush(QBrush(fill));
    
    star->setPen(QPen(QColor(0, 0, 0, percent * 255)));
    
    if (phase > max-3) {
        deleteLater();
    }
}

QPixmap *Flash::pixFlash = 0;

Flash::Flash(qreal x, qreal y, QGraphicsItem *parent, GameBoardScene *scene) 
            : Effect(parent, scene) {
    if (!pixFlash) pixFlash = new QPixmap("pixmaps/flash.png");
    flash = new QGraphicsPixmapItem(*pixFlash, NULL, scene);
    //flash->setOffset(-pixFlash->width()/2, -pixFlash->height()/2);
    flash->setPos(x, y);
    flash->setZValue(scene->getLayerIndex("walls")*10+3);
    timer->start(50);
    advance(0);
}

Flash::~Flash() {
    delete flash;
}

void Flash::advance(int phase) {
    QMatrix matrix;
    if (phase < 10) {
        matrix.scale(.1 * phase, .1 * phase);
    } else if (phase < 20) {
        matrix.scale(.1 * (10.2-phase+10), .1 * (10.2-phase+10));
    } else {
        deleteLater();
        return;
    }
    matrix.translate(-pixFlash->width()/2, -pixFlash->height()/2);
    flash->setMatrix(matrix);
}

void Flash::timerFired() {
    phase += 1;
    advance(phase);
}

